やねうらおさんの233万局面の定跡ファイルを最近使わせてもらったのだが、そのとき、彼のブログで5年も前に3手詰めから11手詰めまでの実戦詰将棋局面を500万例ほど生成して、これをテキストファイルを圧縮した形で無償公開されていることに気が付いた。で、 将棋盤に表示できるようなユーティリティーが欲しい旨のコメントをしている読者もいるみたいだし, これも早速自分のサイトのページに応用させてもらおうかと思った次第である。
で、まずは提供されている圧縮ファイルだが、解凍するとmate3.sfen, mate5.sfen, mate7.sfen, mate9.sfen, mate11.sfen の5つのファイルがでてくる。 それぞれテキストファイルであり、中身はsfen 書式で書かれた局面情報が1行1局面で記述されている。
これをweb siteのページにランダム、あるいは手数と行番号を指定して将棋盤のグラフィックスとして表示させたいわけである。
すべてのデータをブラウザに読み込ませるわけにはいかないので、データ自体はサーバー側に持たせ、ブラウザからは手数と行番号を指定してサーバーに問い合わせ、該当するSFEN一行を取得させて将棋盤上の駒として描画させる、という手法で実現させる。 サーバーでのデータ検索を最適化させるためにmysqlデータベースのテーブルにデータを格納して使う。
データテーブルは一つとして、コラムは手数と問題、各手数の問題カウント、および 通し番号として記録するとしてテーブル構成は以下となる。
Field | Type | Null | Key | default | extra |
---|---|---|---|---|---|
id | INT | NO | PRIMARY | null | auto increment |
sfen | varchar(120) | YES | null | ||
move | int | YES | MUL | null | |
row | int | YES | MUL | null |
このテーブルをまず作っておき、ここにテキストファイルからデータを流し込むわけだ。 で、今度こそPythonを使って見ようとPyCharmを立ち上げ(個人で使う分には無料なんだよね)ブラウザの検索機能で情報を拾いまくりながら、以下のプログラムを作った。
import mysql.connector
from mysql.connector import Error
def create_database_and_table():
try:
# Connect to MySQL server
connection = mysql.connector.connect(
host='localhost',
user='user', # Replace with your MySQL username
password='password' # Replace with your MySQL password
)
cursor = connection.cursor()
# Create database 'mate' if it doesn't exist
cursor.execute("CREATE DATABASE IF NOT EXISTS mate")
cursor.execute("USE mate")
# Create table 'sfens' with indexed columns
cursor.execute("""
CREATE TABLE IF NOT EXISTS sfens (
id INT AUTO_INCREMENT PRIMARY KEY,
sfen VARCHAR(120),
move INT,
row INT,
INDEX (move),
INDEX (row)
)
""")
print("Database and table setup completed.")
except Error as e:
print(f"Error: {e}")
finally:
if connection.is_connected():
cursor.close()
connection.close()
def save_lines_to_database(file_name, move):
try:
# Connect to the 'mate' database
connection = mysql.connector.connect(
host='localhost',
user='user', # Replace with your MySQL username
password='password', # Replace with your MySQL password
database='mate'
)
cursor = connection.cursor()
# Open the file and read lines
with open(file_name, 'r') as file:
linecount=0
while True:
line=file.readline()
if not line:
break
sfen = line.strip() # Remove any trailing whitespace or newline characters
# Insert each line into the 'sfens' table
if sfen.count('/') == 8 and len(sfen.split())==4:
cursor.execute("INSERT INTO sfens (sfen, move,row) VALUES (%s, %s, %s)", (sfen, move,linecount))
else:
print(f"line {linecount} is malformed. skipped: {sfen}")
linecount=linecount+1
if linecount % 1000 == 0:
connection.commit()
if linecount % 25000 == 0:
print(f"{linecount}/1000000 processed")
connection.commit()
# Commit the transaction
connection.commit()
print(f"All lines from '{file_name}' have been saved to the database. problem count: {linecount}")
except Error as e:
print(f"Error: {e}")
except FileNotFoundError:
print(f"Error: File '{file_name}' not found.")
finally:
if connection.is_connected():
cursor.close()
connection.close()
if __name__ == "__main__":
# Create database and table
create_database_and_table()
# array for file name and move value information
file_names = {
'mate3.sfen':3,
'mate5.sfen':5,
'mate7.sfen':7,
'mate9.sfen':9,
'mate11.sfen':11
}
for file_name, move in file_names.items():
save_lines_to_database(file_name, move)
move と counterで検索することになるので、これらのフィールドはインデックスを作成しておく。
20行以上のパイソンを書いたのはおそらく初めてだが、 なるほどユーザーが多いわけだ。
このパイソンスクリプトを走らせてみる。 上のコードでは各行にスラッシュが8個ある、のと、スペースで分解したアレイ素子の因子が4つになる、というのを valid SFENの簡易判定基準とし、それ以外の行はスキップする構造にしてあったのだが、なんとここで10件近くのスキップが発生した。 テキスト行の情報も表示するようになっていたので ファイルをのぞいてみると、sfenが2行くっついた、つまり改行が抜けている個所が何件かあるのが分かった。 プログラムで生成したはずのファイルに何故にこのようなイレギュラリティが発生するのか不思議ではある。 とにかく手作業でこれらの行を分割し、テーブルをいったん削除して再度の挑戦を行った。Pythonのmysql connectorが優秀なのか、パソコンのハードを更新したからなのかはよくわからないが、500万件10分もかからず終わってしまった。
実は500万件なかったのである。mysqlのデータベースが言うには実際には以下の件数の局面が入っていた。ただこれで目くじら立てるのは野暮というものだ。
3手 998,405件
5 手998,827件
7 手999,071件
9 手999,673件
11 手999,998件
サーバーにPHPでAPIポイントをつくり、例えば /api/mate/3/1245というようなHTTPリクエストをサーバーに送れば、3手詰め、1245行目のsfenがjson formatでかえってくるような仕組みを作る。
ブラウザ側のほうはReactとほぼ同じように使えるPREACTをViteとTypeScriptのTool chainを使用しバタバタと書き上げて、出来上がったのがこのページ。 上の数字をもう一度よく見てもらいたいが、 200問くらいの問題集でも一冊全部解くのはなかなか根気がいるのに、いったい誰がこの圧倒的な数の暴力に立ち向かうというのだ?(ちなみに私は高校時代に買った内藤詰将棋200選をまだ全部解いてない)
やねうらおさんのブログにもかいてあるのだが、これは妙手が入った詰将棋とは違って実戦詰将棋的な問題集になる。 ほとんど並べ詰めのようなものもあれば、少し考える必要のあるものもある。 しかしなのだ。 例えば、この局面 ランダムにピックアップしたものだが、

最初に2二金打ち、同金としてから4二桂成 同玉以下は 尻にと金をすべらせていってからの飛車成りまでの送り詰めで9手と言っても難しい詰めではない。 詰将棋だと言って出されれば級位者でも解ける問題だ。 ただ実戦となるとこの局面で4五の桂馬が5三と3三を封鎖しており、さらに金を捨てて、3一の金をどかせれば尻金で詰む、そして4一と金のとき5二玉と逃げれば6一飛成で早く詰む、と局面の駒配置がよく見えなければ詰めようとも思わないわけで、実際これくらいの局面で3切れのShogi warsでは初段、下手すると2段レベルとの対戦でも手駒の金は温存したいと、初手から4二桂成と角を取ってくる可能性は自分の経験から言ってかなり高い。
だとすると、この類の局面を大量にながめて勘を鍛えておくことは棋力向上の役に立つのかもしれない。
それはさておき、ここまでできたなら将棋エンジンもつけて回答も導きだせるようにしたらどうだと言われそうだが、残念ながらそちらのほうの知見は自分はまったく持っていないのであった。思うにサーバーにエンジンを実装してというかバーチャルマシンを一台、それもパーフォーマンスの高いやつを立ち上げて将棋エンジンを常駐させ、これのAPIをたたいて正解を求めるというようなイメージなんだが、いかにもリソース費用がかかりそうだ。lishogiのサイトなどは実現しているみたいだが、どうしているのだろうか。 そのうちだれかが無料のAPIサービスを提供してくれないかと無想するわけである。